<template>
  <div class="sliderVerify">
    <div class="imgBox">
      <!-- <img src="../assets/images/1.png" alt="" /> -->
      <canvas ref="canvasImgRef" width="278" height="155"></canvas>
      <canvas
        :style="{ left: left + 'px' }"
        ref="canvasBlockRef"
        class="canvasBlock"
        width="63"
        height="155"
      ></canvas>
      <el-icon color="#fff" size="20px" class="ico cursorP" @click="onRefresh"
        ><Refresh
      /></el-icon>
    </div>

    <div class="sliderContainer">
      <!-- <div class="txt">验证成功</div> -->
      <span v-show="resultTxt">{{ resultTxt }}</span>
      <div class="sliderMask" :class="result" :style="{ width: left + 'px' }">
        <!-- @mousemove="onMousemove($event)" -->
        <!-- @mouseup="onMouseup" -->
        <div
          class="slider"
          @mousedown="onMousedown"
          :style="{ left: left + 'px' }"
        >
          <!-- <el-iconc><DArrowRight /></el-iconc> -->
          <el-icon><DArrowRight /></el-icon>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, onBeforeUnmount } from "vue";
type Result = "resolv" | "reject" | "pending"; // Promise 状态
interface Emit {
  (event: "onSucceed"): void;
  (event: "onError"): void;
}
interface Props {
  getImageAPI: () => RES<string>;
}

const props = defineProps<Props>();
const emit = defineEmits<Emit>();
const canvasImgRef = ref<HTMLCanvasElement>();
const canvasBlockRef = ref<HTMLCanvasElement>();
// const value = ref(10);
const left = ref(0);
const result = ref<Result>("pending");
const resultTxt = ref("向右滑动填充拼图");
const DEFAULTS = {
  width: 280, // canvas宽度
  height: 155, // canvas高度
  PI: Math.PI,
  sliderL: 42, // 滑块边长
  sliderR: 9, // 滑块半径
  offset: 5, // 容错偏差
  loadingText: "正在加载中...",
  failedText: "再试一次",
  barText: "向右滑动填充拼图",
  repeatIcon: "fa fa-repeat",
  maxLoadCount: 3,
  localImages: function () {
    // console.log('这里');
    return "images/Pic" + Math.round(Math.random() * 4) + ".jpg";
  },
  // verify: function (arr, url) {
  //   // console.log(57, { arr, url });
  //   var ret = false;
  //   $.ajax({
  //     url: url,
  //     data: {
  //       datas: JSON.stringify(arr),
  //     },
  //     dataType: "json",
  //     type: "post",
  //     async: false,
  //     success: function (result) {
  //       ret = JSON.stringify(result);
  //       // console.log("返回结果：" + ret);
  //     },
  //   });
  //   return ret;
  // },
  remoteUrl: null,
};

let isMouseDown = false;
let originX = 0;
let value = 0;

// 随机数
const getRandomNumberByRange = function (start: number, end: number) {
  return Math.round(Math.random() * (end - start) + start);
};

// 获取图片
const getImage = async () => {
  const res = await props.getImageAPI();

  if (!res) return;
  createImage(res.data);
};

// 创建图片
const createImage = (url: string) => {
  const imgCtx: CanvasRenderingContext2D =
    canvasImgRef.value!.getContext("2d")!;
  const blockCtx: CanvasRenderingContext2D =
    canvasBlockRef.value!.getContext("2d")!;

  const img = new Image();
  // img.src = "https://tucdn.wpon.cn/2023/03/10/4391ffba09b7f.jpg";
  // img.src = "/1.png";
  img.src = url;
  resultTxt.value = "正在加载中...";

  img.onload = () => {
    resultTxt.value = "向右滑动填充拼图";
    var L = DEFAULTS.sliderL + DEFAULTS.sliderR * 2 + 3; // 滑块实际边长

    var x = getRandomNumberByRange(L + 10, DEFAULTS.width - (L + 10));
    var y = getRandomNumberByRange(
      10 + DEFAULTS.sliderR * 2,
      DEFAULTS.height - (L + 10)
    );
    // console.log(1.6, x, y, L);
    value = x;
    // 通过修改 width 清空画布
    canvasBlockRef.value!.width = L;
    createPolygon(imgCtx, "fill", x, y);
    createPolygon(blockCtx, "clip", 0, y);
    imgCtx.drawImage(img, 0, 0, DEFAULTS.width - 2, DEFAULTS.height);
    blockCtx.drawImage(img, -x, 0, DEFAULTS.width - 2, DEFAULTS.height);
  };

  img.onerror = () => {
    console.log("失败");
    createImage("/1.png");
  };
};

// 创建多边形
const createPolygon = (
  ctx: CanvasRenderingContext2D,
  operation: "fill" | "clip",
  x: number,
  y: number
) => {
  // console.log(66, ctx);
  if (!ctx) return;
  ctx.clearRect(0, 0, DEFAULTS.width, DEFAULTS.height);
  var l = DEFAULTS.sliderL;
  var r = DEFAULTS.sliderR;
  var PI = DEFAULTS.PI;

  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI);
  ctx.lineTo(x + l, y);
  ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI);
  ctx.lineTo(x + l, y + l);
  ctx.lineTo(x, y + l);
  ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true);
  ctx.lineTo(x, y);
  ctx.lineWidth = 2;
  ctx.fillStyle = "rgba(255, 255, 255, 0.7)";
  ctx.strokeStyle = "rgba(255, 255, 255, 0.7)";
  ctx.stroke();
  ctx[operation]();
  ctx.globalCompositeOperation = "destination-over";
};

// 按住
const onMousedown = (e: MouseEvent) => {
  // console.log(113, "按住");
  if (resultTxt.value === "正在加载中...") return;
  isMouseDown = true;
  originX = e.clientX;
  resultTxt.value = "";
};

// 松开
const onMouseup = (e: MouseEvent) => {
  if (!isMouseDown) return;
  isMouseDown = false;
  const eventX = e.clientX;
  const section = 30; // 区间
  // console.log(117, "松开", eventX, value);
  // console.log(
  //   "+10: ",
  //   eventX + section >= value,
  //   "-10: ",
  //   eventX - section <= value
  // );
  if (eventX + section >= value && eventX - section <= value) {
    // console.log("通过");
    result.value = "resolv";
    emit("onSucceed");
  } else {
    // console.log("不通过");
    emit("onError");
    result.value = "reject";
    setTimeout(() => {
      onRefresh();
      resultTxt.value = "再试一次";
    }, 500);
  }
};

// 移动
const onMousemove = (e: MouseEvent) => {
  if (!isMouseDown) return;
  // console.log("移动", isMouseDown);
  var eventX = e.clientX;
  var eventY = e.clientY;
  const moveX = eventX - originX;
  if (moveX < 0 || moveX + 60 > DEFAULTS.width) return false;

  left.value = moveX - 1;
};

// 刷新
const onRefresh = () => {
  // console.log("刷新");
  result.value = "pending";
  left.value = 0;
  // createImage("https://tucdn.wpon.cn/2023/03/10/4391ffba09b7f.jpg");
  getImage();
};

onMounted(() => {
  // createImage("https://tucdn.wpon.cn/2023/03/10/4391ffba09b7f.jpg");
  getImage();
  window.addEventListener("mousemove", onMousemove);
  window.addEventListener("mouseup", onMouseup);
});

onBeforeUnmount(() => {
  window.removeEventListener("mousemove", onMousemove);
  window.removeEventListener("mouseup", onMouseup);
});
</script>

<style scoped lang="less">
.sliderVerify {
  width: 278px;
  // color: #fff;
  .imgBox {
    background: #ccc;
    width: 278px;
    height: 155px;
    position: relative;
    img {
      width: 100%;
      height: 100%;
    }

    & > * {
      position: absolute;
      top: 0;
      left: 0;
    }

    .canvasBlock {
      left: 10px;
    }

    .ico {
      position: absolute;
      left: 90%;
      top: 10px;
      // z-index: 3;
    }
  }

  .sliderContainer {
    height: 40px;
    background-color: #f7f9fa;
    height: 40px;
    border-radius: 2px;
    border: 1px solid #e6e8eb;
    position: relative;
    text-align: center;
    line-height: 40px;
    user-select: none;

    .sliderMask {
      height: 100%;
      background-color: #d1e9fe;

      .slider {
        position: absolute;
        left: 0;
        top: 0;
        width: 40px;
        height: 40px;
        background: #fff;
        box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
        cursor: pointer;
      }

      &.pending {
        background-color: #d1e9fe;
        .slider {
          background: #fff;
          &:hover {
            background: #1991fa;
            transition: background 0.2s linear;
          }
        }
      }

      &.resolv {
        background-color: #d2f4ef;
        .slider {
          background: #52ccba;
        }
      }

      &.reject {
        background: #fce1e1;
        .slider {
          background: #f57a7a;
        }
      }
    }

    // .txt {
    //   position: relative;
    //   // z-index: 3;
    //   color: #000;
    //   line-height: 40px;
    //   text-align: center;
    // }
  }
}
</style>
